#include "tacs.h"

TAC* tac_create(int _type, row* _target, row* _op1, row* _op2) {
	TAC* tac = (TAC*)calloc(1, sizeof(TAC));
	tac->type = _type;
	tac->target = _target;
	tac->op1 = _op1;
	tac->op2 = _op2;
	tac->prev = NULL;
	tac->next = NULL;
	return tac;
}

TAC* tac_join(TAC* l1, TAC* l2) {
	TAC* t;
	t = NULL;
	//fprintf(stderr, "\njoin");	

	//fprintf(stderr, "\nJoining %d e %d ", l1->type, l2->type); 
	if(l1 == NULL) {
		return l2;	
	}

	if(l2 == NULL ){
		return l1;	
	}

	//fprintf(stderr, "\njoin for");

	for(t = l2; t->prev != NULL; t = t->prev);

	//fprintf(stderr, "\neofor");

	t->prev = l1;
	return l2;
}

void tac_print_single(TAC* t) {
	if(t == NULL) {
		return;
	}

	switch(t->type) {
		case TAC_SYMBOL:
			fprintf(stderr, "\nTAC_SYMBOL ");	
			break;

		case TAC_LABEL:	
			fprintf(stderr, "\nTAC_LABEL ");
			break;

		case TAC_MOVE:	
			fprintf(stderr, "\nTAC_MOVE ");
			break;

		case TAC_REF:
			fprintf(stderr, "\nTAC_REF ");
			break;

		case TAC_DEREF:	
			fprintf(stderr, "\nTAC_DEREF ");
			break;

		case TAC_ADD:
			fprintf(stderr, "\nTAC_ADD ");
			break;

		case TAC_SUB:
			fprintf(stderr, "\nTAC_SUB ");
			break;

		case TAC_MUL:
			fprintf(stderr, "\nTAC_MUL ");
			break;

		case TAC_DIV:
			fprintf(stderr, "\nTAC_DIV ");
			break;

		case TAC_LE:
			fprintf(stderr, "\nTAC_LE ");
			break;

		case TAC_GE:
			fprintf(stderr, "\nTAC_GE ");
			break;

		case TAC_EQ:
			fprintf(stderr, "\nTAC_EQ ");
			break;

		case TAC_NE:
			fprintf(stderr, "\nTAC_NE ");
			break;

		case TAC_AND:
			fprintf(stderr, "\nTAC_AND ");
			break;

		case TAC_OR:
			fprintf(stderr, "\nTAC_OR ");
			break;

		case TAC_G:
			fprintf(stderr, "\nTAC_G ");
			break;

		case TAC_L:
			fprintf(stderr, "\nTAC_L ");
			break;

		case TAC_BEGINFUN:
			fprintf(stderr, "\nTAC_BEGINFUN ");
			break;

		case TAC_ENDFUN:
			fprintf(stderr, "\nTAC_ENDFUN ");
			break;

		case TAC_IFZ:
			fprintf(stderr, "\nTAC_IFZ ");
			break;

		case TAC_JUMP:
			fprintf(stderr, "\nTAC_JUMP ");
			break;

		case TAC_CALL:
			fprintf(stderr, "\nTAC_CALL ");
			break;

		case TAC_ARG:
			fprintf(stderr, "\nTAC_ARG ");
			break;

		case TAC_RET:
			fprintf(stderr, "\nTAC_RET ");
			break;

		case TAC_PRINT:
			fprintf(stderr, "\nTAC_PRINT ");
			break;

		case TAC_READ:
			fprintf(stderr, "\nTAC_READ ");
			break;

		case TAC_VEC:
			fprintf(stderr, "\nTEC_VEC ");
			break;

		case TAC_VECI:
			fprintf(stderr, "\nTAC_VECI ");
			break;

        case TAC_VARI:
            fprintf(stderr, "\nTAC_VARI ");
            break;
        
		case TAC_VECR:
			fprintf(stderr, "\nTAC_VECR ");
			break;

		case TAC_VECW:
			fprintf(stderr, "\nTAC_VECW ");
			break;

		default:
			fprintf(stderr, "(---) \n");
			break;
	}
	
	if(t->target != NULL) {
		aux_print(t->target);	
	}
	else {
		fprintf(stderr, " NULL");	
	}

	if(t->op1 != NULL) {
		aux_print(t->op1);	
	}
	else {
		fprintf(stderr, " NULL");	
	}

	if(t->op2 != NULL) {
		aux_print(t->op2);	
	}
	else {
		fprintf(stderr, " NULL");	
	}
}

void aux_print(row* _symbol) {
	switch(_symbol->type) {
		case SYMBOL_UNDEFINED:
			fprintf(stderr, " UNDEFINED");
			break;

		case SYMBOL_LIT_INTEGER:
			fprintf(stderr, " %s", _symbol->value);
			break;

		case SYMBOL_LIT_TRUE:
			fprintf(stderr, " TRUE");
			break;

		case SYMBOL_LIT_FALSE:
			fprintf(stderr, " FALSE");
			break;

		case SYMBOL_LIT_CHAR:
			fprintf(stderr, " %s", _symbol->value);
			break;

		case SYMBOL_LIT_STRING:
			fprintf(stderr, " %s", _symbol->value);
			break;

		case SYMBOL_IDENTIFIER:
			fprintf(stderr, " %s", _symbol->value);
			break;

		default:
			fprintf(stderr, "(---) \n");
			break;
	}
}

void tac_print_list(TAC* first) {
	TAC* t;
	t = first;

	while(t != NULL) {
		tac_print_single(t);
		t = t->next;
	}
}

TAC* tac_reverse(TAC* last) {
	TAC *first = NULL;

	if(last == NULL) {
		return NULL;
	}	

	for(first = last; first->prev; first = first->prev) {
		first->prev->next = first;
	}
	return first;
}
